#lang r5rs
(define (accumulate op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
          (accumulate op initial (cdr sequence)))))

(define (map1 p sequence)
  (accumulate (lambda (x y) (cons (p x) y)) '() sequence))
(define (append1 seq1 seq2)
  (accumulate cons seq2 seq1))
(define (length sequence)
  (accumulate (lambda (x y) (+ 1 y)) 0 sequence))


(display (append1 (list 1 2 3) (list 4 5 6)))
(newline)
(display (length (list 1 2 3 4 5 6)))
(newline)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (horner-eval x sequence)
  (accumulate (lambda (a b) (+ a (* b x))) 0 sequence))
(display (horner-eval 2 (list 1 3 0 5 0 1)))
(newline)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (count-leaves t)
  (accumulate (lambda (x y)
                (if(pair? x)
                   (+ (count-leaves x) y)
                   (+ 1 y)))
              0
              t))
(define (count-leavess t)
  (accumulate (lambda (x y) (+ x y)) (map (lambda (x)
                                            (if (pair? x)
                                                (count-leavess x)
                                                1)) t)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (accumulate-n op init seqs)
  (if (null? (car seqs))
      '()
      (cons (accumulate op init (map (lambda (x) (car x)) seqs))
            (accumulate-n op init (map (lambda (x) (cdr x)) seqs)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (foldr1 op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
          (foldr1 op initial (cdr sequence)))))

;(define (foldl1 op initial sequence)
;  (if (null? sequence)
;      initial
;      (op (foldl1 op initial (cdr sequence))
;          (car sequence))))

(define (foldl1 op initial sequence)
  (define (iter result rest)
    (if (null? rest)
        result
        (iter (op result (car rest))
              (cdr rest))))
  (iter initial sequence))
(display (foldl1 / 1 (list 1 2 3 4)))
(newline)
(display (foldr1 / 1 (list 1 2 3 4)))
(newline)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (reverse1 l)
  (foldl1 (lambda (x y) (cons y x)) '() l))
(define (reverse2 l)
  (foldr1 (lambda (x y) (append y (if(not(pair? x)) (list x) x))) '() l))

(display (reverse1 (list 1 2 3 4)))
(newline)
(display (reverse2 (list 1 2 3 4)))
(newline)